/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
 *
 */

import { noop } from '@baize/wdk';
import { FileSet, TaskDetails } from '@ohos/hvigor';
import fse from 'fs-extra';
import path from 'path';

import { BuildArtifactConst, BuildDirConst } from '../../const/build-directory-const.js';
import { DeviceTypeConst } from '../../const/device-type-const.js';
import { AbilityTypeEnum } from '../../enum/ability-type-enum.js';
import { CodeType } from '../../enum/code-type-enum.js';
import { LegacyAbilityModel } from '../../model/ability/legacy-ability-model.js';
import { LegacyModuleModelImpl } from '../../model/module/legacy-module-model-impl.js';
import { LegacyTargetSourceSetModel } from '../../model/source-set/source-set-model.js';
import { LoaderEnv } from '../../options/loader-env.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';
import { TaskNames } from '../common/task-names.js';
import { CompileNode } from '../compile-node.js';
import { ModuleTargetData } from '../data/hap-task-target-data.js';
import { ModuleTaskService } from '../service/module-task-service.js';
import { TargetTaskService } from '../service/target-task-service.js';

import { LegacyHookCompileResource } from './hook/legacy-hook-compile-resource.js';
import { LegacyGenerateJsManifest } from './legacy-generate-js-manifest.js';
import { LegacyGenerateLoaderJson } from './legacy-generate-loader-json.js';

/**
 * 调用loader编译老模型的js/ets源码
 *
 * @since 2022/1/20
 */
export class LegacyCompileNode extends CompileNode {
  protected log: OhosLogger = OhosLogger.getLogger(LegacyCompileNode.name);
  protected readonly manifestDir: string;
  protected readonly resourceTablePath: string;
  protected readonly rawFileResource: string;

  constructor(taskService: TargetTaskService, codeType: CodeType, taskDetails: TaskDetails = TaskNames.LegacyFATask.COMPILE_NODE) {
    super(taskService, codeType, taskDetails);

    // 依赖manifest.json的生成
    this.manifestDir = this.pathInfo.getIntermediatesLegacyManifestJson();
    const relatedEntryModules = this.service.getRelatedEntryModules();
    const moduleType = this.service.getModuleModel().getModuleType();
    const entryResDir = ModuleTaskService.checkEntryModules(moduleType, relatedEntryModules) ? relatedEntryModules![0] : '';
    this.resourceTablePath = path.resolve(this.pathInfo.getIntermediatesRes(), entryResDir, BuildArtifactConst.RESOURCE_TABLE_TXT);
    this.rawFileResource = path.resolve(this.pathInfo.getIntermediatesRes(), entryResDir, BuildDirConst.RESTOOL_BUILD_RESOURCES, BuildDirConst.RAW_FILE);
  }

  declareOutputFiles(): FileSet {
    return new FileSet().addEntry(this.aceModuleBuild, { isDirectory: true });
  }

  declareInputFiles(): FileSet {
    const fileSet = new FileSet()
      .addEntry(this.manifestDir, { isDirectory: true })
      .addEntry(this.aceBuildJsonDir, { isDirectory: true })
      .addEntries(this.getAllExistDependentMainPath())
      .addEntries(this.getAllExistHarSrcPath(), { isDirectory: true });
    const resourceDirs: string[] = this.targetService.getResourceDirs();
    if (resourceDirs.length > 0) {
      fileSet.addEntry(this.resourceTablePath);
    }
    if (fse.existsSync(this.rawFileResource)) {
      fileSet.addEntry(this.rawFileResource, { isDirectory: true });
    }
    if (this.sourcePath && fse.existsSync(this.sourcePath)) {
      fileSet.addEntry(this.sourcePath, { isDirectory: true });
    }
    if (this.aceSuperVisualPath && fse.existsSync(this.aceSuperVisualPath)) {
      fileSet.addEntry(this.aceSuperVisualPath, { isDirectory: true });
    }
    return fileSet;
  }

  initTaskDepends() {
    this.declareDepends(LegacyGenerateJsManifest.name);
    this.declareDepends(LegacyHookCompileResource.name);
    this.declareDepends(LegacyGenerateLoaderJson.name);
  }

  taskShouldDo(): boolean {
    return this.targetData.getTargetDeviceTypeClasses().includes(DeviceTypeConst.RICH) && super.taskShouldDo();
  }

  protected async doTaskAction(): Promise<void> {
    const subTaskName = 'generate compile-ArkTs-or-JS-component command';
    const subDurationEvent = this.durationEvent.createSubEvent(subTaskName, '');
    subDurationEvent.start();

    const abilityObjs: LegacyAbilityModel[] = (this.moduleModel as LegacyModuleModelImpl).getLegacyAbilities(this.targetData.getTargetName());
    this.checkLocalDependency(abilityObjs, this.log);
    this.validateAbility(this.log);
    for (const abilityInfo of abilityObjs) {
      if (abilityInfo.getSrcLanguage() !== this.codeType) {
        continue;
      }
      const cmdEnv: LoaderEnv = {
        ...this.commonOption,
        abilityType: abilityInfo.getType(),
        aceManifestPath: path.resolve(this.manifestDir, abilityInfo.getRelateSrcPath(), BuildArtifactConst.LEGACY_MANIFEST_JSON),
        appResource: this.resourceTablePath,
        rawFileResource: this.rawFileResource,
        aceModuleRoot: path.resolve(this.sourcePath!, abilityInfo.getRelateSrcPath()),
        aceModuleBuild: path.resolve(this.aceModuleBuild, abilityInfo.getRelateSrcPath()),
        cachePath: path.resolve(this.getTaskTempDir(this.targetData), abilityInfo.getRelateSrcPath()),
        aceSuperVisualPath: path.resolve(this.aceSuperVisualPath, abilityInfo.getRelateSrcPath()),
        aceBuildJson: path.resolve(this.aceBuildJsonDir, abilityInfo.getRelateSrcPath(), BuildArtifactConst.LOADER_JSON),
      };

      await this.doRealLoaderCompile(
        cmdEnv,
        (targetData: ModuleTargetData, abilityPath: string) => {
          this.moveReleaseMap(targetData, this.log, abilityPath);
        },
        [this.targetData, `js/${abilityInfo.getRelateSrcPath()}`],
        subDurationEvent,
        [0, 1],
      );
    }

    // js fa ohosTest need compile testRunner
    await this.compileTestRunner();
  }

  private async compileTestRunner() {
    const nctr = this.needCompileTestRunner();
    if (!nctr[0]) {
      return;
    }
    const subTaskName = 'generate compile-ArkTs-or-JS-component command for test runner';
    const subTestDurationEvent = this.durationEvent.createSubEvent(subTaskName, '');
    subTestDurationEvent.start();

    const testRunnerPath = nctr[1]!;
    const testEnv: LoaderEnv = {
      ...this.commonOption,
      abilityType: AbilityTypeEnum.TEST_RUNNER,
      appResource: this.resourceTablePath,
      rawFileResource: this.rawFileResource,
      aceModuleRoot: path.resolve(this.sourcePath!, testRunnerPath),
      aceModuleBuild: path.resolve(this.aceModuleBuild, testRunnerPath),
      cachePath: path.resolve(this.getTaskTempDir(this.targetData), testRunnerPath),
    };

    await this.doRealLoaderCompile(testEnv, noop, [], subTestDurationEvent, [0, 1]);
  }

  /**
   * 判断是否需要编译testRunner
   *
   * @returns {[boolean, string | undefined]} 判断结果
   */
  protected needCompileTestRunner(): [boolean, string | undefined] {
    const targetName = this.targetData.getTargetName();
    const sourceSetModel = <LegacyTargetSourceSetModel>this.moduleModel.getSourceSetByTargetName(targetName);
    const testRunnerPath = sourceSetModel.getLegacyModuleTargetRes().getConfigJsonOpt()?.module?.testRunner?.srcPath;
    return [targetName === 'ohosTest' && testRunnerPath !== undefined && this.codeType === CodeType.JS, testRunnerPath];
  }
}
